package com.mp.approvalreq.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.dao.*;
import com.mp.approvalreq.dao.impl.GlobalSettingDaoImpl;
import com.mp.approvalreq.dao.impl.ModifyDaoImpl;
import com.mp.approvalreq.dao.impl.TemplateDaoImpl;
import com.mp.approvalreq.dao.impl.TemplateFolderDaoImpl;
import com.mp.approvalreq.entity.*;
import com.mp.approvalreq.entity.po.ComponentGroup;
import com.mp.approvalreq.entity.po.GlobalSetting;
import com.mp.approvalreq.entity.vo.Component;
import com.mp.approvalreq.service.TemplateServiceServant;
import com.mp.approvalreq.util.*;
import com.mp.user.entity.User;
import com.mp.user.service.UserServicePrx;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.jdbc.util.DBUtils;
import com.plusmoney.util.Utils;
import com.qq.tars.client.util.ServantUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;

public class TemplateServantImpl implements TemplateServiceServant {

    private static final Logger logger = LoggerFactory.getLogger(TemplateServantImpl.class);

    @Override
    public Template getTemplateDetail(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);
            GlobalSettingDao globalSettingDao = new GlobalSettingDaoImpl(connection);

            Template template = templateDao.selectTemplateDetailById(query.getTemplateId());
            if (template == null) {
                throw new RpcServerLogicalException(1, "该模板已被修改，请重新加载");
            }
            //如果该模板的审批流程是~~~条件比较
            if ("Condition".equals(template.getRequestFlow())) {
                User user = new User();
                user.setCompanyId(template.getCompanyId());
                List<ConditionFlow> conditionFlows = templateDao.selectConditionFlowList(template.getTemplateId());
                template.setConditionFlow(conditionFlows);
            }
            // 调整适用范围
            resetRange(template);

            // 移除离职审批人
            resetFlow(template);

            if (Objects.equals(template.getIsFinancial(), 1) && StringUtils.isEmpty(template.getFinancialFlow())) {
                GlobalSetting globalSetting = globalSettingDao.selectGlobalSetting(query.getCompanyId());
                template.setFinancialFlow(globalSetting.getFinancialFlow());
            }

            // 校验旧版本查看含有组件集多选和新版关联组件
            try {
                if (!query.canShowMultipleChosenAndRelatedComponent()) {
                    List<Integer> TYPES = Arrays.asList(36, 37, 38, 39);
                    List<TemplateComponent> templateComponents = JSONObject.parseArray(template.getTemplateComponent(), TemplateComponent.class);
                    for (TemplateComponent component : templateComponents) {
                        if (TYPES.contains(component.getType())) {
                            throw new RpcServerLogicalException(1, "请更新大管加版本");
                        }
                    }
                    List<Integer> groupIds = templateComponents.stream().filter(c -> Objects.equals(c.getType(), ContentType.COMPONENT_GROUP)).map(TemplateComponent::getGroupId).collect(Collectors.toList());
                    if (Utils.isNotEmpty(groupIds)) {
                        List<ComponentGroup> groups = selectTemplateDao.selectComponentGroupInfoList(query.getCompanyId(), Utils.list2string(groupIds));
                        for (ComponentGroup group : groups) {
                            for (Component component : group.getComponents()) {
                                if (Objects.equals(component.getType(), ContentType.GROUP_MULTI_CHOSEN)) {
                                    throw new RpcServerLogicalException(1, "请更新大管加版本");
                                }
                            }
                        }
                    }
                }
            } catch (RpcServerLogicalException e) {
                throw e;
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
            }
            return template;
        } catch (Throwable e) {
            throw ErrorUtils.throwError(e, logger);
        } finally {
            DBUtils.release(connection);
        }
    }

    private void resetFlow(Template template) {
        try {
            final List<String> SPECIAL_FLOW = Arrays.asList("default", "Alternative", "Condition", "SP", "DM");
            String requestFlow = template.getRequestFlow();
            if (SPECIAL_FLOW.contains(requestFlow)) {
                return;
            }
            String str = requestFlow.replaceAll("\\|\\|", ",").replaceAll("&&", ",");
            List<String> flowIds = ListHelper.string2StringList(str);
            flowIds.removeIf(s -> !ValidateUtil.isPositiveInteger(s));
            if (Utils.isNotEmpty(flowIds)) {
                UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
                User admin = userServicePrx.getAdminUser(template.getCompanyId());
                List<User> userList = userServicePrx.getUserListByContactIds(Utils.list2string(flowIds));
                for (User user : userList) {
                    if (!Objects.equals(user.getQuit(), true)) {
                        continue;
                    }
                    boolean isFlowChanged = removeRequestFlow(user, template, admin);
                    if (isFlowChanged) {
                        logger.info("移除离职审批人,移除前:{}-----移除后:{}", requestFlow, template.getRequestFlow());
                        EmailUtils.sendMail("移除离职审批人", template);
                    }
                }
            }
        } catch (Throwable throwable) {
            logger.error(throwable.getMessage(), throwable);
        }
    }

    private void resetRange(Template template) {
        try {
            if (StringUtils.isNotEmpty(template.getDepartmentId()) && !"0".equals(template.getDepartmentId())) {
                UserServicePrx userService = ServantUtils.getObject(UserServicePrx.class);
                List<User> userList = userService.getUserListByDepartmentIds(template.getCompanyId(), template.getDepartmentId());
                Set<Integer> contactIds = new HashSet<>(), companyInfoIds = new HashSet<>();
                for (User user : userList) {
                    contactIds.add(user.getContactId());
                    companyInfoIds.add(user.getCompanyInfoId());
                }
                contactIds.addAll(ListHelper.string2IntegerList(template.getRangeSpecific()));
                companyInfoIds.addAll(ListHelper.string2IntegerList(template.getCompanyInfoIdRange()));

                template.setRangeSpecific(ListHelper.collectionToString(contactIds));
                template.setCompanyInfoIdRange(ListHelper.collectionToString(companyInfoIds));
            }
        } catch (Throwable throwable) {
            logger.error(throwable.getMessage(), throwable);
            EmailUtils.sendMail("调整适用范围出错", throwable);
        }
    }

    @Override
    public void handleQuitTemplate(User user) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);

        try {
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            List<Template> templates = templateDao.selectAllEffectiveTemplate(user.getCompanyId());

            User admin = userServicePrx.getAdminUser(user.getCompanyId());
            List<Template> templatesToUpdate = new ArrayList<>();
            for (Template template : templates) {
                String requestFlow = template.getRequestFlow();
                boolean isFlowChanged = removeRequestFlow(user, template, admin);

                boolean isCcChanged = removeCc(user, template);

                if (isFlowChanged || isCcChanged) {
                    logger.info("审批人:{}=====>{}", requestFlow, template.getRequestFlow());
                    logger.info("抄送人:{}=====>{}", template.getCc(), template.getCc());
                    templatesToUpdate.add(template);
                }
            }
            if (Utils.isEmpty(templatesToUpdate)) {
                return;
            }
            DBUtils.begin(connection);
            templateDao.updateTemplateFlowAndCc(templatesToUpdate);
            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            EmailUtils.sendErrorMail("交接异常", JSONObject.toJSONString(e));
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void addModifyRecord(Template template) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);

        try {
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            ModifyDao modifyDao = new ModifyDaoImpl(connection);

            User user = template.getUser();

            List<ApprovalModify> modifies = new ArrayList<>();
            if ("delete".equals(template.getModifyType())) {
                // 删除
                ApprovalModify modify = new ApprovalModify(template);
                modify.setTitle(String.format("%s删除模版\"%s\"", user.getContactName(), template.getTemplateName()));
                modifies.add(modify);
            } else if ("add".equals(template.getModifyType())) {
                // 添加
                ApprovalModify modify = new ApprovalModify(template);
                modify.setTemplateId(template.getTemplateInsertId());
                modify.setTitle(String.format("%s新增模版\"%s\"", user.getContactName(), template.getTemplateName()));
                modifies.add(modify);
            } else {
                // 修改
                Template oldTemplate = templateDao.selectTemplateDetailById(template.getTemplateId());
                if (RequestFlowType.CONDITION.equals(oldTemplate.getRequestFlow())) {
                    List<ConditionFlow> conditionFlows = templateDao.selectConditionFlowList(oldTemplate.getTemplateId());
                    oldTemplate.setConditionFlow(conditionFlows);
                }
                modifies = ModifyUtils.getUpdateModifies(oldTemplate, template);
            }
            if (Utils.isEmpty(modifies)) {
                return;
            }
            logger.info("data:{}", JSONObject.toJSONString(modifies));
            DBUtils.begin(connection);
            modifyDao.insertBatchModifies(modifies);
            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            EmailUtils.sendErrorMail("插入记录异常", JSONObject.toJSONString(e));
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<ApprovalModify> getModifyList(Query query) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            ModifyDao modifyDao = new ModifyDaoImpl(connection);

            return modifyDao.selectModifyList(query.getCompanyId(), query.getPage(), query.getDataNum());

        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<Template> getTemplateListForAmoeba(Integer companyId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            List<Template> templates = templateDao.selectAllEffectiveTemplate(companyId);

            final List<Integer> numberTypes = Arrays.asList(ContentType.NUMBER, ContentType.MONEY, ContentType.TOTAL_MONEY);
            templates.removeIf(template -> {
                List<TemplateComponent> components = JSONObject.parseArray(template.getTemplateComponent(), TemplateComponent.class);
                List<TemplateComponent> list = components.stream().filter(t -> numberTypes.contains(t.getType())).collect(Collectors.toList());
                if (Utils.isEmpty(list)) {
                    return true;
                }
                template.setTemplateComponent(JSONObject.toJSONString(list));
                return false;
            });

            return templates;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<TemplateFolder> getTemplateFolders(Integer companyId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            TemplateFolderDao templateFolderDao = new TemplateFolderDaoImpl(connection);

            List<TemplateFolder> folders = templateFolderDao.selectTemplateFolders(companyId);
            for (TemplateFolder folder : folders) {
                if (Utils.isNotEmpty(folder.getTemplates())) {
                    List<Integer> distinctIds = folder.getTemplates().stream().distinct().collect(Collectors.toList());
                    if (distinctIds.size() != folder.getTemplates().size()) {
                        folder.setTemplates(distinctIds);
                    }
                }
            }
            return folders;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void saveTemplateFolder(TemplateFolder templateFolder) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);

        try {
            TemplateFolderDao templateFolderDao = new TemplateFolderDaoImpl(connection);
            TemplateDao templateDao = new TemplateDaoImpl(connection);
            ModifyDao modifyDao = new ModifyDaoImpl(connection);


            boolean isNewFolder = Utils.isNull(templateFolder.getId()) || templateFolder.getId() == 0;
            List<TemplateFolder> templateFolders = templateFolderDao.selectTemplateFolders(templateFolder.getCompanyId());
            List<Template> templates = templateDao.selectAllEffectiveTemplate(templateFolder.getCompanyId());
            Map<Integer, Template> templateMap = templates.stream().collect(Collectors.toMap(Template::getAncestorId, t -> t, (a, b) -> b));
            Map<Integer, String> folderNameMap = templateFolders.stream().collect(Collectors.toMap(TemplateFolder::getId, TemplateFolder::getName));

            List<ApprovalModify> modifies = new ArrayList<>();
            List<TemplateFolder> foldersToUpdate = new ArrayList<>();
            Map<Integer, Integer> beforeMap = new HashMap<>();

            for (TemplateFolder folder : templateFolders) {
                if (Utils.isEmpty(folder.getTemplates())) {
                    continue;
                }
                for (Integer templateId : folder.getTemplates()) {
                    beforeMap.put(templateId, folder.getId());
                }
            }
            logger.info("beforeMap:{}", beforeMap);

            for (TemplateFolder folder : templateFolders) {
                if (Utils.isEmpty(folder.getTemplates()) || Utils.isEmpty(templateFolder.getTemplates())) {
                    continue;
                }
                boolean modified = folder.getTemplates().removeAll(templateFolder.getTemplates());
                if (modified) {
                    foldersToUpdate.add(folder);
                }
            }

            try {
                if (Utils.isNotEmpty(templateFolder.getTemplates())) {
                    for (Integer templateAncestorId : templateFolder.getTemplates()) {
                        Integer beforeId = beforeMap.getOrDefault(templateAncestorId, 0);
                        if (Objects.equals(templateFolder.getId(), beforeId)) {
                            // 未修改适用范围
                            continue;
                        }
                        Template template = templateMap.get(templateAncestorId);
                        if (Utils.isNull(template)) {
                            continue;
                        }
                        // 修改模板分组记录
                        User user = templateFolder.getUser();
                        ApprovalModify modify = new ApprovalModify();
                        modify.setCompanyId(user.getCompanyId());
                        modify.setCompanyInfoId(user.getCompanyInfoId());
                        modify.setTitle(String.format("%s 修改模板 「%s」 分组", user.getContactName(), template.getTemplateName()));
                        modify.setDetail(String.format("%s → %s", folderNameMap.getOrDefault(beforeId, ""), templateFolder.getName()));
                        modify.setTemplateId(template.getTemplateId());
                        modify.setTemplateAncestorId(template.getAncestorId());
                        modifies.add(modify);
                    }
                }

            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                EmailUtils.sendMail("修改审批分组记录出错", e);
            }

            if (isNewFolder) {
                // 添加分组记录
                try {
                    User user = templateFolder.getUser();
                    ApprovalModify modify = new ApprovalModify();
                    modify.setCompanyId(user.getCompanyId());
                    modify.setCompanyInfoId(user.getCompanyInfoId());
                    modify.setTitle(String.format("%s 新建 「%s」 审批分组", user.getContactName(), templateFolder.getName()));
                    modify.setTemplateId(0);
                    modify.setTemplateAncestorId(0);
                    modifies.add(modify);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    EmailUtils.sendMail("修改审批分组记录出错", e);
                }
            } else {
                foldersToUpdate.add(templateFolder);

                try {
                    if (!Objects.equals(templateFolder.getName(), folderNameMap.get(templateFolder.getId()))) {
                        User user = templateFolder.getUser();
                        ApprovalModify modify = new ApprovalModify();
                        modify.setCompanyId(user.getCompanyId());
                        modify.setCompanyInfoId(user.getCompanyInfoId());
                        modify.setTitle(String.format("%s 修改审批分组 「%s」 审批分组名称", user.getContactName(), folderNameMap.get(templateFolder.getId())));
                        modify.setDetail(String.format("%s → %s", folderNameMap.get(templateFolder.getId()), templateFolder.getName()));
                        modify.setTemplateId(0);
                        modify.setTemplateAncestorId(0);
                        modifies.add(modify);
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    EmailUtils.sendMail("修改审批分组记录出错", e);
                }
            }

            DBUtils.begin(connection);
            if (isNewFolder) {
                templateFolderDao.insertTemplateFolder(templateFolder);
            }
            if (Utils.isNotEmpty(foldersToUpdate)) {
                templateFolderDao.updateBatchTemplateFolder(foldersToUpdate);
            }
            if (Utils.isNotEmpty(modifies)) {
                modifyDao.insertBatchModifies(modifies);
            }
            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void sortTemplateFolder(Integer companyId, List<Integer> ids) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);

        try {
            TemplateFolderDao templateFolderDao = new TemplateFolderDaoImpl(connection);

            List<TemplateFolder> templateFolders = templateFolderDao.selectTemplateFolders(companyId);
            if (Utils.isEmpty(templateFolders)) {
                return;
            }
            for (TemplateFolder folder : templateFolders) {
                if (!ids.contains(folder.getId())) {
                    continue;
                }
                folder.setSort(ids.indexOf(folder.getId()) + 1);
            }

            DBUtils.begin(connection);
            templateFolderDao.updateBatchTemplateFolder(templateFolders);
            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void deleteTemplateFolder(Integer companyId, Integer folderId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);

        try {
            TemplateFolderDao templateFolderDao = new TemplateFolderDaoImpl(connection);

            DBUtils.begin(connection);
            templateFolderDao.deleteTemplateFolder(folderId, companyId);
            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void deleteTemplateFolder(TemplateFolder templateFolder) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);

        try {
            TemplateFolderDao templateFolderDao = new TemplateFolderDaoImpl(connection);
            ModifyDao modifyDao = new ModifyDaoImpl(connection);

            User user = templateFolder.getUser();

            templateFolder = templateFolderDao.selectTemplateFolderById(templateFolder.getId());
            if (Utils.isNull(templateFolder)) {
                throw new RpcServerLogicalException(1, "审批分组不存在");
            }

            ApprovalModify modify = new ApprovalModify();
            modify.setCompanyId(user.getCompanyId());
            modify.setCompanyInfoId(user.getCompanyInfoId());
            modify.setTitle(String.format("%s 删除审批分组 「%s」", user.getContactName(), templateFolder.getName()));
            modify.setTemplateId(0);
            modify.setTemplateAncestorId(0);

            DBUtils.begin(connection);
            templateFolderDao.deleteTemplateFolder(templateFolder.getId(), user.getCompanyId());
            modifyDao.insertBatchModifies(Collections.singletonList(modify));
            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private boolean removeCc(User user, Template template) {
        if (StringUtils.isEmpty(template.getCc())) {
            return false;
        }
        List<String> list = ListHelper.string2StringList(template.getCc());
        boolean isChanged = list.remove(String.valueOf(user.getContactId()));
        if (isChanged) {
            String cc = Utils.isEmpty(list) ? null : ListHelper.list2string(list);
            template.setCc(cc);
        }
        return isChanged;
    }

    private boolean removeRequestFlow(User user, Template template, User admin) {
        String quitUser = String.valueOf(user.getContactId());
        if (isWithoutUser(template.getRequestFlow(), quitUser)) {
            return false;
        }
        List<String> requestFlows = ListHelper.string2StringList(template.getRequestFlow());
        List<String> newFlows = new ArrayList<>();
        int removeIndex = 0;
        for (String requestFlow : requestFlows) {
            if (isWithoutUser(requestFlow, quitUser)) {
                newFlows.add(requestFlow);
                continue;
            }
            removeIndex = requestFlows.indexOf(requestFlow);
            if (requestFlow.contains("||")) {
                String[] subFlows = requestFlow.split("\\|\\|");
                StringBuilder sb = new StringBuilder();
                for (String subFlow : subFlows) {
                    if (quitUser.equals(subFlow)) {
                        continue;
                    }
                    sb.append("||").append(subFlow);
                }
                newFlows.add(sb.substring(2));
            } else if (requestFlow.contains("&&")) {
                String[] subFlows = requestFlow.split("&&");
                StringBuilder sb = new StringBuilder();
                for (String subFlow : subFlows) {
                    if (quitUser.equals(subFlow)) {
                        continue;
                    }
                    sb.append("&&").append(subFlow);
                }
                newFlows.add(sb.substring(2));
            }
        }
        if (removeIndex >= newFlows.size()) {
            newFlows.add(String.valueOf(admin.getContactId()));
        }
        template.setRequestFlow(ListHelper.list2string(newFlows));
        return true;
    }

    private boolean isWithoutUser(String requestFlow, String quitUser) {
        requestFlow = requestFlow.replaceAll("\\|\\|", ",").replaceAll("&&", ",");
        List<String> flows = ListHelper.string2StringList(requestFlow);
        for (String flow : flows) {
            if (flow.equals(quitUser)) {
                return false;
            }
        }
        return true;
    }
}
